/**
 * 
 */
package org.swing.utility.common.chars;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.DefaultByteBufHolder;
import io.netty.util.IllegalReferenceCountException;

import java.nio.charset.StandardCharsets;

/**
 * @author lqnhu
 *
 */
public class ReadOnlyUtfBuf extends AbstractReadOnlyUtfBuf implements
		ReadableCharBuf, ByteBufHolder {
	private final ByteBuf data;

	public ReadOnlyUtfBuf(ByteBuf data) {
		if (data == null) {
			throw new NullPointerException("data");
		}
		this.data = data;
	}

	// these two are intended to allow for propagating cache metadata to derived
	// buffers
	ReadOnlyUtfBuf(ByteBuf data, int cacheInstance) {
		if (data == null) {
			throw new NullPointerException("data");
		}
		this.data = data;
		this.packedIndexCache = cacheInstance;
	}

	ReadOnlyUtfBuf(ByteBuf data, int charDelta, int byteIndex) {
		this(data, packIndexCache(charDelta, byteIndex));
	}

	public ReadOnlyUtfBuf(ByteBufHolder charBuf) {
		this(charBuf.content());
	}

	
	public byte getByte(int index) {
		return content().getByte(index);
	}

	
	public int getByteLength() {
		return content().readableBytes();
	}

	
	public ReadableCharBuf getSubSequenceForByteBounds(int start, int end) {
		return new ReadOnlyUtfBuf(data.slice(start, end - start));
	}

	
	public String toString() {
		return content().toString(StandardCharsets.UTF_8);
	}

	
	public int compareTo(ReadableCharBuf o) {
		if (o instanceof ReadOnlyUtfBuf) {
			return ByteBufUtil.compare(((ReadOnlyUtfBuf) o).content(),
					content());
		} else {
			return super.compareTo(o);
		}
	}

	
	public ByteBuf toByteBuf() {
		return content();
	}

	
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj instanceof ReadableCharBuf) {
			return ByteBufUtil.equals(((ReadableCharBuf) obj).toByteBuf(),
					content());
		}
		return false;
	}

	
	public ByteBuf content() {
		if (data.refCnt() <= 0) {
			throw new IllegalReferenceCountException(data.refCnt());
		}
		return data;
	}

	
	public ByteBufHolder copy() {
		return new DefaultByteBufHolder(data.copy());
	}

	
	public ByteBufHolder duplicate() {
		return new DefaultByteBufHolder(data.duplicate());
	}

	
	public int refCnt() {
		return data.refCnt();
	}

	
	public ByteBufHolder retain() {
		data.retain();
		return this;
	}

	
	public ByteBufHolder retain(int increment) {
		data.retain(increment);
		return this;
	}

	
	public boolean release() {
		return data.release();
	}

	
	public boolean release(int decrement) {
		return data.release(decrement);
	}
}
